import { ICellRender } from './types';
import { Cell } from '../cors/cell';
import { NFont } from '../types/style.interface';
import { formatFont } from '../utils/draw-helper/text/format-font-style';
import { getTextRect } from '../utils/draw-helper/text/get-text-rect';
import { clip } from '../utils/clip'
const _equalArray = (arr1: any[], arr2: any[]) => {
    for(let i = 0; i < arr1.length; i++) {
        if(arr1[i] !== arr2[i]) return false;
    }
    return true;
}
export class RenderBase {
    protected _value: any = undefined;
    protected _deps: any[] = [];
    public memory(callback: (...args: any[]) => any, deps: any[]) {
        if(this._value === undefined || !_equalArray(this._deps, deps)) {
            this._deps = deps;
            let result = callback();
            this._value = result;
        }
        return this._value;
    }
}

export abstract class ARenderBase implements ICellRender{
    public abstract cell: Cell;
    public abstract init(value: any):void;
    protected abstract ctx: CanvasRenderingContext2D;
    protected abstract conf: {enlarge: number};
    render(rectPossition: TRect, clipRect: TRect, font: NFont.IFont): void {
        if(this.cell === null || this.cell === undefined || this.cell.value === null || this.cell.value.getActualValue().type === 'empty') return;
        let _value = this.cell.value.getActualValue().toString();
        if(_value.length === 0) return;
        let textArr: IDrawTextArr[] = [];
        let _font = {
            ...font,
            size: font.size * this.conf.enlarge
        }
        if(font.autoWrap) {
            let style = formatFont(_font.size, _font.family, _font.style, _font.weight);
            let idx = 0;
            for(let i = 1; i < _value.length; i++) {
                let _str = _value.substring(idx, i);
                let rect = getTextRect(this.ctx, _str, style);
                if(_value[i] === '\n') {
                    textArr.push({
                        text: _str,
                        font: font,
                        height: rect.h,
                        width: rect.w,
                        style: style
                    });
                    idx = i + 1;
                    continue;
                }
                if(rect.w > rectPossition.w) {
                    if(_str.length === 1) {
                        textArr.push({
                            text: _str,
                            font: font,
                            height: rect.h,
                            width: rect.w,
                            style: style
                        });
                        idx = i;
                        continue;
                    }
                    let frondStr = _value.substring(idx, i-1);
                    let frondSize = getTextRect(this.ctx, frondStr, style);
                    textArr.push({
                        text: frondStr,
                        font: font,
                        height: frondSize.h,
                        width: frondSize.w,
                        style: style
                    });
                    idx = --i;
                    continue;
                }
            }
            let endStr = _value.substring(idx);
            if(endStr.length > 0) {
                let rect = getTextRect(this.ctx, endStr, style);
                textArr.push({
                    text: endStr,
                    font: font,
                    height: rect.h,
                    width: rect.w,
                    style: style
                });
            }
        } else {
            let style = formatFont(_font.size, _font.family, _font.style, _font.weight);
            let idx = 0;
            for(let i = 1; i < _value.length; i++) {
                if(_value[i] === '\n') {
                    let tempStr = _value.substring(idx, i)
                    let rect = getTextRect(this.ctx, tempStr, style);
                    textArr.push({
                        text: tempStr,
                        font: font,
                        width: rect.w,
                        height: rect.h,
                        style: style
                    });
                    idx = i + 1;
                }
            }
            let endStr = _value.substring(idx);
            let rect = getTextRect(this.ctx, endStr, style);
            textArr.push({text: endStr, font: font, width: rect.w, height: rect.h, style: style});
        }
        let allHeight = (() => {
            let height = 0;
            textArr.forEach(item => height += item.height);
            height += (textArr.length - 1) * 2 * this.conf.enlarge;
            return height;
        })();
        let startY = 0;
        switch(font.vertical) {
            case NFont.EVertical.top:
                startY = 0;
                break;
            case NFont.EVertical.bottom:
                if(allHeight > rectPossition.h) {
                    startY = 0;
                } else {
                    startY = rectPossition.h - allHeight;
                }
                break;
            default:
                if(allHeight > rectPossition.h) {
                    startY = 0;
                } else {
                    startY = (rectPossition.h - allHeight) / 2;
                }
        }
        clip(this.ctx, () => {
            this.ctx.rect(clipRect.x, clipRect.y, clipRect.w, clipRect.h);
        }, () => {
            this.ctx.textBaseline = 'hanging';
            for(let i = 0; i < textArr.length; i++) {
                let startX = 0;
                switch(font.horizontally) {
                    case NFont.EHorizontally.center:
                        if(textArr[i].width > rectPossition.w) {
                            startX = 0;
                        } else {
                            startX = (rectPossition.w - textArr[i].width) / 2;
                        }
                        break;
                    case NFont.EHorizontally.right:
                        if(textArr[i].width > rectPossition.w) {
                            startX = 0;
                        } else {
                            startX = rectPossition.w - textArr[i].width;
                        }
                        break;
                }
                this.ctx.font = textArr[i].style;
                this.ctx.fillStyle = textArr[i].font.color || '#0A2143';
                this.ctx.fillText(textArr[i].text, rectPossition.x + startX , rectPossition.y + startY);
                if(font.decoration || font.decoration !== NFont.EDecoration.none) {
                        this.ctx.save();
                        this.ctx.beginPath();
                        if(font.decoration === NFont.EDecoration.underline) {
                            this.ctx.moveTo(rectPossition.x + startX, rectPossition.y + startY + textArr[i].height * 1.2);
                            this.ctx.lineTo(rectPossition.x + startX + textArr[i].width,rectPossition.y + startY + textArr[i].height * 1.2);
                        }
                        if(font.decoration === NFont.EDecoration.overline) {
                            this.ctx.moveTo(rectPossition.x + startX, rectPossition.y + startY);
                            this.ctx.lineTo(rectPossition.x + startX + textArr[i].width,rectPossition.y + startY);
                        }
                        if(font.decoration === NFont.EDecoration.lineThrough) {
                            this.ctx.moveTo(rectPossition.x + startX, rectPossition.y + startY + (textArr[i].height * 1.2) / 2);
                            this.ctx.lineTo(rectPossition.x + startX + textArr[i].width,rectPossition.y + startY + (textArr[i].height * 1.2) / 2);
                        }
                        this.ctx.lineWidth = 1;
                        this.ctx.strokeStyle = font.color;
                        this.ctx.closePath();
                        this.ctx.stroke();
                        this.ctx.restore();
                    // }
                }
                startY += textArr[i].height + 2 * this.conf.enlarge;
                if(startY > clipRect.y + clipRect.h) {
                    break;
                }
            }
        });
    }
}
interface IDrawTextArr {
    text: string;
    height: number;
    font: NFont.IFont;
    width: number;
    style: string;
}